#pragma once

#include "sfc/core/macro.h"
#include "sfc/core/str.h"

namespace sfc::reflect {

template <class T>
auto type_id() -> usize {
  static const int id = 0;
  return reinterpret_cast<usize>(&id);
}

template <class T>
auto type_name() -> str::Str {
#if defined(__clang__)
  const auto PREFIX = sizeof("str::Str sfc::reflect::type_name() [T = ") - 1;
  const auto SUFFIX = sizeof("]") - 1;
#elif defined(__GNUC__)
  const auto PREFIX = sizeof("sfc::str::Str sfc::reflect::type_name() [with T = ") - 1;
  const auto SUFFIX = sizeof("]") - 1;
#else
  const auto PREFIX = 0U;
  const auto SUFFIX = 0U;
#endif
  const auto len = sizeof(__PRETTY_FUNCTION__) - 1 - PREFIX - SUFFIX;
  return str::Str{__PRETTY_FUNCTION__ + PREFIX, len};
}

template <auto X>
auto value_name() -> str::Str {
#if defined(__clang__)
  const auto PREFIX = sizeof("str::Str sfc::reflect::value_name() [T = ") - 1;
  const auto SUFFIX = sizeof("]") - 1;
#elif defined(__GNUC__)
  const auto PREFIX = sizeof("sfc::str::Str sfc::reflect::value_name() [with T = ") - 1;
  const auto SUFFIX = sizeof("]") - 1;
#else
  const auto PREFIX = 0U;
  const auto SUFFIX = 0U;
#endif
  const auto len = sizeof(__PRETTY_FUNCTION__) - 1 - PREFIX - SUFFIX;

  const auto full_name = str::Str{__PRETTY_FUNCTION__ + PREFIX, len};
  const auto name_indx = full_name.rfind(':').map([](auto x) { return x + 1; }).unwrap_or(0);
  return full_name[{name_indx, _}];
}

}  // namespace sfc::reflect
